package com.general.framework.thread;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;

/**
 * Semaphore 是一种同步辅助类，在Java中用于控制对共享资源的访问量。
 * <p>
 * 以下是Semaphore的一些主要应用场景，以及一些框架或中间件中使用Semaphore的例子：
 * <p>
 * * 数据库连接池：在数据库连接池中，Semaphore可以用来限制同时访问数据库的线程数量，避免因为过多的并发连接导致数据库性能下降或崩溃。这是Semaphore的一个非常典型的应用场景
 * <p>
 * * 线程池：在线程池中，Semaphore可以用来控制同时执行的任务数量，确保系统的稳定性和性能
 * <p>
 * * 文件访问：当多个线程或进程需要同时访问同一个文件时，Semaphore可以用来确保在任何时刻只有一个线程或进程在访问文件，避免文件访问冲突
 * <p>
 * * 资源分配：在某些场景下，资源是有限的，例如内存、CPU等。Semaphore可以用来控制对这些资源的访问数量，确保系统的正常运行
 * <p>
 * * 限流器：Semaphore可以实现限流器的功能，通过限制访问某种资源的数量来实现限流
 * <p>
 * * 互斥锁：Semaphore也可以用来实现互斥锁的功能，确保同一时刻只有一个线程可以执行特定的代码段
 * <p>
 * * Hystrix：在Hystrix中就有基于Semaphore的资源隔离策略，用于控制并发执行的线程数量，以防止系统过载
 */
public class SemaphoreExample {

    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        Semaphore semaphore = new Semaphore(3);

        for (int i = 0; i < 10; i++) {
            executor.submit(() -> {
                try {
                    // acquire()方法用于从Semaphore中获取一个许可。如果没有可用的许可，线程将阻塞，直到有许可被释放。一旦获取许可成功，Semaphore的可用许可数量将减一
                    semaphore.acquire();
                    System.out.println("Thread " + Thread.currentThread().getName() + " 线程抢到许可,剩余许可 " + semaphore.availablePermits());
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    // release()方法用于释放一个许可。释放许可后，Semaphore的可用许可数量将增加一。如果有其他线程在等待许可，它们将被唤醒并尝试获取许可
                    semaphore.release();
                    System.out.println("Thread " + Thread.currentThread().getName() + " 线程抢到许可,剩余许可 " + semaphore.availablePermits());
                }
            });
        }
        executor.shutdown();
    }
}